<?php

namespace app\api\server;
use app\api\model\MemberArithmeticalPower as MemberArithmeticalPowerModel;
use app\api\model\MiningArithmetical as MiningArithmeticalModel;
use app\api\model\Member as MemberModel;
use think\cache\driver\Redis;
use app\api\model\MemberLevel as MemberLevelModel;
use app\common\model\MiningPledge as MiningPledgeModel;

class Arithmetical
{

    public function __construct(){
        //算力矿机订单
        $this->MApower = new MemberArithmeticalPowerModel();
        //矿机
        $this->mining_arithmetical = new MiningArithmeticalModel();

        $this->redis = new Redis(config('cache.stores.redis'));
    }

    /**
     * 计算所有用户算力 及 全网算力 ,并扣除已质押矿机算力
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function member_arithmetical(){
        //查询运行中的矿机(非预售状态)
        $mining = $this->mining_arithmetical::whereIn('type','2,3,4')->select();
        $maid = [];
        $mining_list = [];
        foreach ($mining as $v){
            $maid[] = $v['id'];
            $mining_list[$v['id']] = $v;
        }

        //查询对应的矿机订单
        $all = $this->MApower::whereIn('maid',$maid)->where('surplus_arithmetical','>','0')->where('pay_status','=',1)->order('id asc')->select();

        if(empty($all)) return [];

        $all = $all->toArray();

        //查询所有用户
        $all_member = MemberModel::getAll();
        $memberAll = [];
        foreach ($all_member as $v){
            $memberAll[$v['id']] = $v;  //用户ID作为key
        }

        //全网总算力
        $total_arithmetical = 0;
        //用户算力
        $member_all = [];

        $MemberList = MemberLevelModel::getMemberList();
        $level = [];
        $level['max'] = 0;  //最大等级
        //循环用户等级
        foreach ($MemberList as $v){
            $level[$v['id']] = $v;
            if($v['level'] == 0) $level[0] = $v;    //初始等级
            if($level['max'] < $v['level']) $level['max'] = $v['level'];
        }

        $mining_mid = [];

        foreach ($all as $v){
            //用户不存在跳出循环
            if(empty($memberAll[$v['mid']])) continue;

            if(empty($member_all[$v['mid']])){
                $member_all[$v['mid']] = [
                    'arithmetical'=>0,  //总算力
                    'team_arithmetical' =>  0,  //团队算力
                    'mining'=>[],   //矿机算力
                    'mid'=>$v['mid'],   //用户ID
                    'pledge'    =>  0,//我的质押算力
                    'mining_volume' =>  0,  //我的总开采量
                    'surplus_arithmetical'  =>  0,
                    'recommend_arithmetical'  =>  $memberAll[$v['mid']]['recommended_computing'], //矿机购买奖励（投票算力）
                    'zhiya_recommend_arithmetical'  =>  round(MiningPledgeModel::sum_arithmetical($v['mid'],[],2),8),
                    'total_zhiya_recommend_arithmetical' => 0,
                    'pid'   =>  $memberAll[$v['mid']]['pid'],
                    'team_nozhiya'  =>  0,//社区投票算力 (团队总算力,非质押)
                ];

                //扣除质押算力
                if($member_all[$v['mid']]['recommend_arithmetical'] < $memberAll[$v['mid']]['deduct_recommended']){
                    $member_all[$v['mid']]['recommend_arithmetical'] = 0;
                }else{
                    $member_all[$v['mid']]['recommend_arithmetical'] = bcsub($member_all[$v['mid']]['recommend_arithmetical'],$memberAll[$v['mid']]['deduct_recommended'],8);
                }

                $member_all[$v['mid']]['total_zhiya_recommend_arithmetical'] = $member_all[$v['mid']]['zhiya_recommend_arithmetical'];
                //记录矿机产出的用户
                $mining_mid[] = $v['mid'];
                //用户等级
                $member_all[$v['mid']]['level'] = $level[$memberAll[$v['mid']]['level_id']];
            }

            //计算质押算力              矿机算力 * 质押倍数
            $arithmetical_num = bcmul($v['pledge_money'],$mining_list[$v['maid']]['pledge_multiple'],8);    //计算算力
            //我的质押算力
            $member_all[$v['mid']]['pledge'] = bcadd($arithmetical_num,$member_all[$v['mid']]['pledge'],8);

            //我的实际算力 = 质押算力 + 矿机剩余开采量
            $arithmetical_num = bcadd($arithmetical_num,$v['surplus_arithmetical'],8);
            //统计用户算力
            $member_all[$v['mid']]['arithmetical'] = bcadd($arithmetical_num,$member_all[$v['mid']]['arithmetical'],8);
            //总开采量
            $member_all[$v['mid']]['mining_volume'] = bcadd($v['arithmetical_power'],$member_all[$v['mid']]['mining_volume'],8);

            //计算该用户真实算力 (当前开采量)
            $member_all[$v['mid']]['surplus_arithmetical'] = bcadd($member_all[$v['mid']]['surplus_arithmetical'],$v['surplus_arithmetical'],8);

            //用户每台矿机产出数据
            $member_all[$v['mid']]['mining'][] = [
                'id'    =>  $v['id'],   //矿机ID
                'arithmetical'  =>  $arithmetical_num,   //矿机产出算力
                'surplus_arithmetical'  =>  $v['surplus_arithmetical'], //我剩余算力
                'maid'  =>  $v['maid'],
                'pledge_money'    =>  bcmul($v['pledge_money'],$mining_list[$v['maid']]['pledge_multiple'],8)    //计算质押算力
            ];

            //统计全网算力
            $total_arithmetical = bcadd($total_arithmetical,$arithmetical_num,8);
        }

        foreach ($mining_mid as $v){
            if(!empty($memberAll[$v]['pid'])){
                //递归获得用户团队算力
                $member_all = $this->team_power($v,$memberAll[$v]['pid'],$memberAll,$member_all,$member_all[$v]['level']['level'],$level,$member_all[$v]['level']['mining_range']);
            }
        }

        //加入团队算力 到 全网总算力
        foreach ($member_all as &$v){
            if($v['team_arithmetical'] > 0) $total_arithmetical = bcadd($total_arithmetical,$v['team_arithmetical'],8);
            //统计全网算力
            $total_arithmetical = bcadd(bcadd($total_arithmetical,$v['recommend_arithmetical'],8),$v['zhiya_recommend_arithmetical'],8);
            //纳入我的总算力
            $v['arithmetical'] = bcadd(bcadd($v['arithmetical'],$v['recommend_arithmetical'],8),$v['zhiya_recommend_arithmetical'],8);
        }

        //更新全网总算力
        $this->redis->set('totalArithmetical',$total_arithmetical);

        return ['total'=>$total_arithmetical,'member'=>$member_all];
    }

    /**
     * 矿机算力 递归团队极差
     * @param $mid  用户ID
     * @param $member   用户列表
     * @param $power_member 用户算力
     * @param $level 上级用户等级
     * @param $memberLevelList 用户等级列表
     * @param int $range 当前团队极差
     */
    public function team_power($mid,$pid,$member,$power_member,$level,$memberLevelList,$range){
        //判断上级用户是否存在
        if(empty($member[$pid])) return $power_member;

        //计算  社区投票算力 (团队总算力,非质押)
        if(!empty($power_member[$pid])) $power_member[$pid]['team_nozhiya'] = bcadd($power_member[$mid]['surplus_arithmetical'],$power_member[$pid]['team_nozhiya'],8);
        //社区质押总算力
        if(!empty($power_member[$pid])) $power_member[$pid]['total_zhiya_recommend_arithmetical'] = bcadd(bcadd($power_member[$mid]['zhiya_recommend_arithmetical'],$power_member[$pid]['total_zhiya_recommend_arithmetical'],8),$power_member[$mid]['pledge'],8);

        //判断上级用户等级是否与当前用户一致
        if($level == $memberLevelList[$member[$pid]['level_id']]['level']){
            //存在有上级用户 执行递归
            if(!empty($member[$pid]['pid'])) $power_member = $this->team_power($mid,$member[$pid]['pid'],$member,$power_member,$level,$memberLevelList,$range);

        }else{
            //计算极差
            $range_disparity = bcdiv(bcsub($memberLevelList[$member[$pid]['level_id']]['mining_range'],$range,8),100,10);
            //当前极差
            $range = $memberLevelList[$member[$pid]['level_id']]['mining_range'];   //更新用户极差
            $level = $memberLevelList[$member[$pid]['level_id']]['level'];  //更新最新用户等级

            //存在有上级用户 执行递归 且等级不为最高级
            if(!empty($member[$pid]['pid']) && $level != $memberLevelList['max']) $power_member = $this->team_power($mid,$member[$pid]['pid'],$member,$power_member,$level,$memberLevelList,$range);

            //计算团队所得 上级不为空 且 极差大于0
            if(!empty($power_member[$member[$pid]['id']]) && $range_disparity > 0){   //上级有算力
                $team_num = 0;
//                //计算用户分配给到的团队极差
//                $team_num = bcmul($power_member[$mid]['arithmetical'],$range_disparity,8);

                //计算用户分配给到的团队极差
                $team_num = bcmul($power_member[$mid]['total_zhiya_recommend_arithmetical'],$range_disparity,8);
                //团队算力极差所得
                $power_member[$member[$pid]['id']]['team_arithmetical'] = bcadd($power_member[$member[$pid]['id']]['team_arithmetical'],$team_num,8);
            }
        }
        return $power_member;
    }

}